package com.znh.entity;

import com.znh.common.Utils;
import com.znh.enums.PieceActionEnum;
import com.znh.enums.PieceInitLocationEnum;
import com.znh.enums.PiecePlayerEnum;

import javax.swing.*;
import java.awt.*;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;

/**
 * @version 1.0
 * @Author znh
 * @Date 2024/5/23 上午10:03
 * @注释 棋子类
 */
public abstract class Piece implements Serializable {

    public Piece(){

    }
    public Piece(int id,String name, Point point, PiecePlayerEnum player, PieceInitLocationEnum initLocation, String imgPath) {
        this.id = id;
        this.name = name;
        this.point = point;
        this.player = player;
        this.initLocation = initLocation;
        this.imgPath = imgPath;
        calXYByPoint();
    }

    public final static int WIDTH = 30; //宽度
    public final static int HEIGHT = 30;    //高度
    public final static int MARGIN = 20;    //棋盘最外围空白间距
    public final static int SPACE = 40;     //棋子之间的间隔

    /**
     * 棋子的id，唯一
     */
    private int id;
    /*
    名称
     */
    private String name;
    //实际绘画坐标
    private int x, y;
    //逻辑坐标
    private Point point;
    //阵营 0:红；1:黑
    private PiecePlayerEnum player;
    //棋子初始状态是在上部分还是下部分
    private PieceInitLocationEnum initLocation;
    //图片路径
    private String imgPath;


    public int getWIDTH() {
        return WIDTH;
    }

    public int getHeight() {
        return HEIGHT;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public Point getPoint() {
        return point;
    }

    public void setPoint(Point point) {
        this.point = point;
        calXYByPoint();
    }

    public PiecePlayerEnum getPlayer() {
        return player;
    }

    public void setPlayer(PiecePlayerEnum player) {
        this.player = player;
    }

    public PieceInitLocationEnum getInitLocation() {
        return initLocation;
    }

    public void setInitLocation(PieceInitLocationEnum initLocation) {
        this.initLocation = initLocation;
    }

    public String getImgPath() {
        return imgPath;
    }

    public void setImgPath(String imgPath) {
        this.imgPath = imgPath;
    }


    /**
     * 从逻辑坐标计算出实际坐标
     */
    public void calXYByPoint() {
        this.x = MARGIN - WIDTH / 2 + (point.x - 1) * SPACE;
        this.y = MARGIN - HEIGHT / 2 + (point.y - 1) * SPACE;
    }

    /**
     * 反转逻辑坐标,同时也将实际坐标翻转
     */
    public void reversePoint(){
        point.setLocation(10-point.x,11-point.y);
        calXYByPoint();
        //位置反转
        initLocation = initLocation==PieceInitLocationEnum.DOWN?PieceInitLocationEnum.UP:PieceInitLocationEnum.DOWN;
    }

    /**
     * 从逻辑坐标计算出棋子中心点实际坐标
     * @param logicPoint 逻辑坐标
     * @return 实际坐标
     */
    public static Point calCenterXYByPoint(Point logicPoint) {
        Point drawPoint=new Point();
        drawPoint.x = (MARGIN - WIDTH / 2 + (logicPoint.x - 1) * SPACE)+WIDTH/2;
        drawPoint.y = (MARGIN - HEIGHT / 2 + (logicPoint.y - 1) * SPACE)+HEIGHT/2;
        return drawPoint;
    }

    /**
     * 绘制棋子
     *
     * @param g
     * @param panel
     */
    public void draw(Graphics g, JPanel panel) {
        Image image = Toolkit.getDefaultToolkit().getImage(imgPath);
        g.drawImage(image, x, y, WIDTH, HEIGHT, panel);
    }

    /**
     * 绘制棋子边框
     *
     * @param g
     * @param panel
     */
    public void drawBorder(Graphics g, JPanel panel) {
        g.drawRect(x, y, WIDTH, HEIGHT);
    }

    /**
     * 判断坐标是否在九宫内
     *
     * @param tp
     * @return 在九宫返回true
     */
    public boolean isJiuGong(Point tp) {
        return (tp.x >= 4 && tp.x <= 6) && ((tp.y >= 1 && tp.y <= 3) || (tp.y >= 8 && tp.y <= 10));
    }

    /**
     * 判断当前坐标到目标坐标是什么动作
     *
     * @param tp
     * @return 动作类型
     */
    public PieceActionEnum action(Point tp) {
        if (tp.x == point.x) {
            //横轴直线
            return PieceActionEnum.LINEY;
        } else if (tp.y == point.y) {
            //竖轴直线
            return PieceActionEnum.LINEX;
        } else if (Math.abs(tp.x - point.x) == Math.abs(tp.y - point.y)) {
            //正斜线
            return PieceActionEnum.FORWARDSLASH;
        } else if ((Math.abs(tp.x - point.x) == 2 && Math.abs(tp.y - point.y) == 1) || (Math.abs(tp.x - point.x) == 1 && Math.abs(tp.y - point.y) == 2)) {
            //日字
            return PieceActionEnum.SUN;
        } else {
            //其他情况
            return null;
        }
    }

    /**
     * 获取当前坐标到目的坐标的步数
     *
     * @param tp     目标坐标
     * @param action 动作
     * @return 步数
     */
    public int getStep(Point tp, PieceActionEnum action) {
        int step;
        switch (action) {
            case LINEX:
                step = Math.abs(tp.x - point.x);
                break;
            case LINEY:
            case FORWARDSLASH:  //正斜线的步数用x和y计算都一样，所以这里直接合并到Y的case
                step = Math.abs(tp.y - point.y);
                break;
            default:
                step = 0;
        }
        return step;
    }

    /**
     * 统计到目标坐标之间的棋子数量（不包括起点和终点）
     *
     * @param tp     目标坐标
     * @param action 动作
     * @return 到目标坐标之间的棋子数量（不包括起点和终点）
     */
    public int countRoutePiece(Point tp, PieceActionEnum action) {
        int count = 0;
        int start = 0;
        int end = 0;
        switch (action) {
            case LINEX:
                start = Math.min(point.x, tp.x) + 1;
                end = Math.max(point.x, tp.x) - 1;
                for (; start <= end; start++) {
                    if (GameRule.POINT_PIECE_MAP.containsKey(new Point(start, tp.y))) {
                        count++;
                    }
                }
                break;
            case LINEY:
                start = Math.min(point.y, tp.y) + 1;
                end = Math.max(point.y, tp.y) - 1;
                for (; start <= end; start++) {
                    if (GameRule.POINT_PIECE_MAP.containsKey(new Point(tp.x, start))) {
                        count++;
                    }
                }
                break;
            default:
        }
        return count;
    }

    /**
     * 判断是否蹩脚
     *
     * @param tp 目标坐标
     * @return 蹩脚返回true
     */
    public boolean isBieJiao(Point tp) {
        switch (name) {
            case "xiang":
                return GameRule.POINT_PIECE_MAP.containsKey((new Point((point.x + tp.x) / 2, (point.y + tp.y) / 2)));
            case "ma":
                return (Math.abs(tp.x - point.x) == 2 && Math.abs(tp.y - point.y) == 1//x轴日字
                        && GameRule.POINT_PIECE_MAP.containsKey(new Point((tp.x + point.x) / 2, point.y)))
                        || (Math.abs(tp.x - point.x) == 1 && Math.abs(tp.y - point.y) == 2//y轴日字
                        && GameRule.POINT_PIECE_MAP.containsKey(new Point(point.x, (tp.y + point.y) / 2)));
            default:
                return false;
        }
    }

    /**
     * 判断是否过河
     *
     * @param tp
     * @return 过河返回true
     */
    public boolean isCrossRiver(Point tp) {
        return (initLocation == PieceInitLocationEnum.UP && tp.y > 5)
                || (initLocation == PieceInitLocationEnum.DOWN && tp.y < 6);
    }

    /**
     * 判断前往目标坐标是否为前进
     *
     * @param tp 目标坐标
     * @return 是前进返回true
     */
    public boolean isForward(Point tp) {
        return (initLocation == PieceInitLocationEnum.UP && tp.y > point.y)
                || (initLocation == PieceInitLocationEnum.DOWN && tp.y < point.y);
    }

    /**
     * 判断前往目标坐标是否为后退
     *
     * @param tp 目标坐标
     * @return 是后退返回true
     */
    public boolean isRetreat(Point tp) {
        return (initLocation == PieceInitLocationEnum.UP && tp.y < point.y)
                || (initLocation == PieceInitLocationEnum.DOWN && tp.y > point.y);
    }

    /**
     * 判断是否可以移动
     *
     * @param tp 目的坐标
     * @return
     */
    public abstract boolean isMove(Point tp);


    /**
     *  //模拟移动
     * @param tp
     * @return true:能够成功移动
     */
    public boolean simulateMove(Point tp){
        boolean result =false;
        Piece actionPiece = Utils.deepClone(this);
        Piece atePiece = GameRule.POINT_PIECE_MAP.getOrDefault(tp, null);
        if(atePiece!=null&&atePiece.getPlayer()==actionPiece.getPlayer()){
            //目标坐标有棋子，且与行动棋子阵营相同
            return false;
        }
        //更新棋子坐标
        GameRule.removeCurPhaseMap(actionPiece);
        if (atePiece!=null&&atePiece.getPlayer()!=actionPiece.getPlayer()){
            //吃子
            GameRule.removeCurPhaseMap(atePiece);
        }
        actionPiece.setPoint(tp);
        GameRule.addCurPhaseMap(actionPiece);
        //判断移动后是否被将军
        result=GameRule.NAME_PIECE_MAP.get(GameRule.CUR_ROUND).get("boss").stream()
                .anyMatch(boss -> ((Boss) boss).isNextEat());
        //还原
        GameRule.removeCurPhaseMap(actionPiece);
        actionPiece.setPoint(this.getPoint());
        GameRule.addCurPhaseMap(actionPiece);
        if (atePiece!=null&&atePiece.getPlayer()!=actionPiece.getPlayer()){
            //吃子
            GameRule.addCurPhaseMap(atePiece);
        }
        return !result;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Piece piece = (Piece) o;
        if (id==piece.id) {
            return true;
        } else {
            //导入导入棋谱后棋谱中的行棋记录MEMOS已经有id，和新生成的棋子id不一致
            //如果id不同，名称、阵营、坐标相同也视为相同
            return name==piece.name&&player==piece.player&&point==piece.point;
        }

    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
